package cn.seaboot.flake.jdbc;

import cn.seaboot.commons.core.ClassPathResource;
import cn.seaboot.commons.core.Converter;
import cn.seaboot.commons.file.PropertiesUtils;
import cn.seaboot.commons.reflect.FieldAccess;
import cn.seaboot.commons.reflect.ObjectField;
import cn.seaboot.flake.mapping.ResultMap;
import cn.seaboot.flake.mapping.ResultMapping;
import org.jetbrains.annotations.NotNull;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.persistence.Column;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;

/**
 * @author Mr.css
 * @version 2025-05-15 11:19
 */
public class JdbcUtils {

    /**
     * 读取 driver.properties 文件，构建一个简单的数据源
     * <p>
     * 在日常调试中，非常实用的函数
     *
     * @return -
     * @throws IOException -
     */
    public static DataSource createDataSource() throws IOException {
        try (InputStream is = ClassPathResource.getInputStream("driver.properties")) {
            Properties props = PropertiesUtils.load(is);
            String driver = props.getProperty("driver");
            String url = props.getProperty("url");
            String username = props.getProperty("username");
            String password = props.getProperty("password");
            System.out.println(props);
            return createDataSource(driver, url, username, password);
        }
    }

    /**
     * 构建一个简答的数据源
     * <p>
     * 在日常调试中，非常实用的函数
     *
     * @param driver   驱动
     * @param url      地址
     * @param username 用户名
     * @param password 密码
     * @return DataSource
     */
    public static DataSource createDataSource(String driver, String url, String username, String password) {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * 查询结果转换成 map
     *
     * @param rs    结果集
     * @param len   字段数
     * @param names 每一列的字段名
     * @return -
     * @throws SQLException -
     */
    @NotNull
    public static List<Map<String, Object>> toMap(ResultSet rs, int len, String[] names) throws SQLException {
        List<Map<String, Object>> list = new ArrayList<>();
        while (rs.next()) {
            Map<String, Object> map = new HashMap<>();
            for (int i = 1; i < len; i++) {
                map.put(names[i], rs.getObject(i));
            }
            list.add(map);
        }
        return list;
    }

    /**
     * 查询结果转换成 map
     *
     * @param rs     结果集
     * @param access 每一列的字段名
     * @return -
     * @throws SQLException -
     */
    @NotNull
    public static <T> List<T> toObject(ResultSet rs, FieldAccess access, Map<String, String> mapping) throws SQLException {
        ResultSetMetaData metaData = rs.getMetaData();
        int len = metaData.getColumnCount() + 1;


        ObjectField[] fields = new ObjectField[len];
        for (int i = 1; i < len; i++) {
            String fn = mapping.get(metaData.getColumnName(i));
            fields[i] = access.getField(fn);
        }

        List<T> list = new ArrayList<>();
        Object value;
        while (rs.next()) {
            T obj = access.newInstance();
            for (int i = 1; i < len; i++) {
                ObjectField field = fields[i];
                if (field != null) {
                    value = rs.getObject(i);
                    value = Converter.convert(value, field.getType());
                    field.setValue(obj, value);
                }
            }
            list.add(obj);
        }
        return list;
    }

    /**
     * 从 JPA 注解中，获取 ResultMap
     *
     * @param clazz -
     * @return -
     * @throws SQLException -
     */
    @NotNull
    public static ResultMap getResultMapFromJAP(Class<?> clazz) throws SQLException {
        ResultMap rm = new ResultMap();

        FieldAccess access = FieldAccess.create(clazz);
        List<ResultMapping> mappings = new ArrayList<>();

        ObjectField[] fields = access.getFields();
        for (int i = 1, len = fields.length; i < len; i++) {
            ObjectField field = fields[i];
            Column column = field.getAnnotation(Column.class);
            if (column != null) {
                ResultMapping mapping = new ResultMapping();
                mapping.setColumn(column.name());
                mapping.setProperty(field.getName());
                mapping.setJavaType(field.getType());
                mappings.add(mapping);
            }
        }

        rm.setResultMappings(mappings);
        return rm;
    }
}
